/************************************************************************/
/*   Calibration of the weight scale.                                   */
/************************************************************************/

#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>
#include <stdio.h> 
#include <math.h>
#include "weight_sensor.h"
#include "lcd162.h"
#include "switch.h"
#include "uart.h"
#include "eeprom_.h"

// enter calibration mode timeout, in tenths of second (approx)
#define CALIBRATION_TIMEOUT 30

void Calibration();
void CalibrationEnter();

void CalibrationEnter()
{
		LCDClear();
		LCDDispString("Press S3 to");
		LCDGotoXY(0,1);
		LCDDispString("calibrate.");
		
		for (uint8_t i = CALIBRATION_TIMEOUT; (( i > 0) & (S3() == 0)); i--)
		{
			LCDGotoXY(11,1);
			LCDDispInteger(i/10);
			LCDDispString("  ");
			_delay_ms(100);
		}
		if (S3())
		{
			Calibration();
		} 
}

void Calibration()
{	
	uint16_t cal_weight;
	uint16_t cal_ADC_0;
	uint16_t cal_ADC_F;
	
	LCDClear();
	LCDDispString("Calibration Mode");
	LCDGotoXY(0,1);
	LCDDispString("Use UART");
	//Set new first stage gain to maximum gain
	setFirstStageGain(127);
	_delay_ms(1500);
	
	/**********
	* STEP 1
	**********/
	// No load.
	// Press button (S3).
	
	UARTSendString("No weight. Press S3 to save.");
	UARTSendChar('\r');
	LCDClear();
	LCDDispString("No load");
	while (S3() == 0)
	{
		LCDGotoXY(0,1);
		LCDDispInteger(WeightNoCalibrated());
		LCDDispString("  ");
		_delay_ms(100);
	}

	// Read ADC
	cal_ADC_0 = WeightNoCalibrated();
	UARTSendInteger(cal_ADC_0);
	
	LCDClear();
	// Delay for preventing pressing the button twice
	_delay_ms(1000); 

	/**********
	* STEP 2
	**********/
	// Full load (or well-known load = 1 kg).
	// Press button (S3).

	UARTSendString("Full load. Press S3 to save.");
	UARTSendChar('\r');
	LCDClear();
	LCDDispString("Full load");
	while (S3() == 0)
	{
		LCDGotoXY(0,1);
		LCDDispInteger(WeightNoCalibrated());
		LCDDispString("  ");
		_delay_ms(100);
	}
	cal_ADC_F = WeightNoCalibrated();
	UARTSendInteger(cal_ADC_F);

	/**********
	* STEP 3
	**********/
	LCDClear();
	LCDDispString("Send weight");
	// Receive the weight
	UARTSendString("Send weight in grams + space");
	
	char str[6] = {'\0'};
	uint8_t i = 0;
	str[i] = UARTReadChar();
	while ((str[i] != 32)&(i < 6)) // 32 = space
	{
		i++;
		str[i] = UARTReadChar();
	}
	str[i] = 0;
	sscanf(str,"%u ", &cal_weight);
	
	uint32_t calc_temp = cal_weight;
		
	// Gain = Weight*PreviousGain / ( 2*( ADC_Full - ADC_0 ))
	double gain_total = (calc_temp*1280) / (2*(cal_ADC_F - cal_ADC_0 ));
	double gain_code = (log(gain_total/800)*127)/log(1.6) + 0.5;
	uint8_t code = (uint8_t)gain_code;
	UARTSendString("Gain 1 code: ");
	UARTSendInteger(code);
	EEPROMWriteByte(ADDRESS_CODE,code);
	// Set new first stage gain.
	setFirstStageGain(code);
	
	/**********
	* STEP 4
	**********/
	// New no load
	
	UARTSendString("New no load. Press S3 to save.");
	UARTSendChar('\r');
	LCDClear();
	
	while (S3() == 0)
	{}
	cal_ADC_0 = WeightNoCalibrated();
	EEPROMWriteWord(ADDRESS_NO_LOAD , cal_ADC_0);
	WeightCalibrationUpdate();
	
	UARTSendString("Calibration done.");
	LCDDispString("Done.");
	
	_delay_ms(2000);	
}





